home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Auge 4000
/
Auge 4000 #54 (1991-04-07)(Amiga User Gruppe Einzugsgebiet 4000).zip
/
Auge 4000 #54 (1991-04-07)(Amiga User Gruppe Einzugsgebiet 4000).adf
/
PopUpMenu
/
Source
/
Main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-07
|
14KB
|
489 lines
#include "PopUpMenu.h"
#include "Version.h"
#define REPLYPORTNAME "Reply"
#define IMPDEVPORTNAME "ImpDev"
#define TIMERPORTNAME "Timer"
#define QUITPORTNAME "Quit"
#define INPHANDLNAME "PopUpMenu"
#define SEMAPHORENAME "PopUpMenu"
#define POPUPMSG "\x9B0;33mPopUpMenu\x9B0m "
#define KILLMSG "removed.\n"
#define STARTMSG "installed.\n\xA9 Martin Adrian 1990\n"
#define FAILMSG "failed.\n"
/* Let the text stay for 3s if started from WorkBench */
#define DELAYTIME 150
#define INPHANDLPRI 53
/* Must use kickstart 1.2 or higher */
#define LIBVERSION 33
/* don't know how to find these in C */
#define LVOSetMenuStrip -0x108
#define LVOClearMenuStrip -0x36
#define LVOOnMenu -0xc0
#define LVOOffMenu -0xb4
/* this is for errors in proto/exec.h */
#undef RemSemaphore
#pragma syscall RemSemaphore 25e 901
VOID InitPopUpMenu()
{
IMPORT struct DosLibrary *DosBase;
IMPORT struct IntuitionBase *IntuitionBase;
IMPORT struct GfxBase *GfxBase;
IMPORT struct LayersBase *LayersBase;
IMPORT struct IOStdReq *InputReqBlock;
IMPORT struct MsgPort *TimerPort;
IMPORT struct timerequest *TimerReqBlock;
IMPORT LONGBITS TimerSignal;
IMPORT struct MsgPort *ReplyPort;
IMPORT struct SignalSemaphore PopUpSemaphore;
IMPORT __fptr OldSetMenuStrip, OldClearMenuStrip, OldOnMenu, OldOffMenu;
IMPORT BPTR StdOut;
IMPORT BPTR PopUpSeg;
struct MsgPort *InputDevPort;
struct Interrupt InputReqData;
struct SignalData InputSignals;
LONG MenuUpSigNum, MenuDownSigNum;
LONG MouseMovedSigNum, SelectDownSigNum;
geta4(); /* load global database */
Write(StdOut,POPUPMSG,sizeof(POPUPMSG));
/***********************************
* see if we are already installed *
***********************************/
if (!(ReplyPort = FindPort(REPLYPORTNAME))) {
if (!(ReplyPort = MyCreatePort(REPLYPORTNAME)))
goto CleanUp13;
}
else {
/* yes, popupmenues already installed, tell running task to quit */
struct MsgPort *const QuitPort = MyCreatePort(QUITPORTNAME);
struct IntuiMessage *Message;
if (QuitPort) {
if (Message = BuildIntuiMsg(QuitPort,QUITPOPUPMENU,NULL)) {
/* Send quitmessage */
PutMsg(ReplyPort, (struct Message *)Message);
/* Wait for reply */
WaitPort(QuitPort);
/* get rid of the message */
GetMsg(QuitPort);
FreeMem(Message,sizeof(struct IntuiMessage));
WriteAndClose(KILLMSG, sizeof(KILLMSG));
}
MyDeletePort(QuitPort);
}
goto CleanUp13;
}
/******************
* open libraries *
******************/
if (!(IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library", LIBVERSION)))
goto CleanUp12;
if (!(GfxBase = (struct GfxBase *)
OpenLibrary("graphics.library", LIBVERSION)))
goto CleanUp11;
if (!(LayersBase = (struct LayersBase *)
OpenLibrary("layers.library", LIBVERSION)))
goto CleanUp10;
/************************
* Allocate our signals *
************************/
if ((MenuUpSigNum = AllocSignal(-1)) == -1)
goto CleanUp9;
if ((MenuDownSigNum = AllocSignal(-1)) == -1)
goto CleanUp8;
if ((MouseMovedSigNum = AllocSignal(-1)) == -1)
goto CleanUp7;
if ((SelectDownSigNum = AllocSignal(-1)) == -1)
goto CleanUp6;
/****************************************
* Build connection to the input.device *
****************************************/
if (!(InputDevPort = MyCreatePort(IMPDEVPORTNAME)))
goto CleanUp5;
if ((InputReqBlock = (struct IOStdReq *)
AllocMem(sizeof(struct IOStdReq),
MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
goto CleanUp4;
InputReqBlock->io_Message.mn_Node.ln_Type = NT_MESSAGE;
InputReqBlock->io_Message.mn_Length = sizeof(struct IOStdReq);
InputReqBlock->io_Message.mn_ReplyPort = InputDevPort;
if (OpenDevice("input.device",0,(struct IORequest *)InputReqBlock,0))
goto CleanUp3;
/****************************************
* Bulid connection to the timer.device *
****************************************/
if (!(TimerPort = MyCreatePort(TIMERPORTNAME)))
goto CleanUp3x3;
TimerSignal = 1L << TimerPort->mp_SigBit;
if (!(TimerReqBlock = (struct timerequest *)
AllocMem(sizeof(struct timerequest),
MEMF_CLEAR | MEMF_PUBLIC)))
goto CleanUp3x2;
TimerReqBlock->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
TimerReqBlock->tr_node.io_Message.mn_Length = sizeof(struct timerequest);
TimerReqBlock->tr_node.io_Message.mn_ReplyPort = TimerPort;
if (OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerReqBlock,0))
goto CleanUp3x1;
/* Start Timer (just to be sure that at least one request is sent. */
/* CheckIO doesn't work otherwise, i think) */
QueTimer();
/********************
* Make a semaphore *
********************/
PopUpSemaphore.ss_Link.ln_Name = /*SEMAPHORENAME*/ NULL;
PopUpSemaphore.ss_Link.ln_Pri = 0;
/*
AddSemaphore(&PopUpSemaphore);
*/
InitSemaphore(&PopUpSemaphore);
/**************************************************
* patch intuition functions to use our semaphore *
**************************************************/
if (!(OldSetMenuStrip = SetFunction((struct Library *)IntuitionBase,
LVOSetMenuStrip,MySetMenuStrip)))
goto CleanUp2x4;
if (!(OldClearMenuStrip = SetFunction((struct Library *)IntuitionBase,
LVOClearMenuStrip,MyClearMenuStrip)))
goto CleanUp2x3;
if (!(OldOnMenu = SetFunction((struct Library *)IntuitionBase,
LVOOnMenu,MyOnMenu)))
goto CleanUp2x2;
if (!(OldOffMenu = SetFunction((struct Library *)IntuitionBase,
LVOOffMenu,MyOffMenu)))
goto CleanUp2x1;
/**********************************
* init data for the inputhandler *
**********************************/
InputSignals.PopUpMenuTask = FindTask(0);
InputSignals.MenuUpSig = 1L << MenuUpSigNum;
InputSignals.MenuDownSig = 1L << MenuDownSigNum;
InputSignals.MouseMovedSig = 1L << MouseMovedSigNum;
InputSignals.SelectDownSig = 1L << SelectDownSigNum;
InputSignals.Down = FALSE; /* menubutton is not down. (who cares) */
/****************************
* startup the inputhandler *
****************************/
InputReqData.is_Node.ln_Pri = INPHANDLPRI; /* must come before intuition */
InputReqData.is_Node.ln_Name = INPHANDLNAME;
InputReqData.is_Data = (APTR)&InputSignals;
InputReqData.is_Code = (VOID *)PopUpHandler;
InputReqBlock->io_Command = IND_ADDHANDLER;
InputReqBlock->io_Data = (APTR)&InputReqData;
DoIO((struct IORequest *)InputReqBlock);
/***************************************
* tell the user that everything is ok *
***************************************/
WriteAndClose(VERSION STARTMSG, sizeof(VERSION STARTMSG));
PopUpMainLoop(&InputSignals);
CleanUp1:
/* remove inputhandler */
InputReqBlock->io_Command = IND_REMHANDLER;
InputReqBlock->io_Data = (APTR)&InputReqData;
DoIO((struct IORequest *)InputReqBlock);
/* restore intuition functions */
SetFunction((struct Library *)IntuitionBase,LVOOffMenu,OldOffMenu);
CleanUp2x1:
SetFunction((struct Library *)IntuitionBase,LVOOnMenu,OldOnMenu);
CleanUp2x2:
SetFunction((struct Library *)IntuitionBase,LVOClearMenuStrip,OldClearMenuStrip);
CleanUp2x3:
SetFunction((struct Library *)IntuitionBase,LVOSetMenuStrip,OldSetMenuStrip);
CleanUp2x4:
/* remove semaphore */
/* RemSemaphore(&PopUpSemaphore);*/
/* close timer.device */
CloseDevice((struct IORequest *)TimerReqBlock);
CleanUp3x1:
FreeMem(TimerReqBlock,sizeof(struct timerequest));
CleanUp3x2:
MyDeletePort(TimerPort);
CleanUp3x3:
/* close input.device */
CloseDevice((struct IORequest *)InputReqBlock);
CleanUp3:
DeleteStdIO(InputReqBlock);
CleanUp4:
MyDeletePort(InputDevPort);
CleanUp5:
/* Free allocated signals */
FreeSignal(SelectDownSigNum);
CleanUp6:
FreeSignal(MouseMovedSigNum);
CleanUp7:
FreeSignal(MenuDownSigNum);
CleanUp8:
FreeSignal(MenuUpSigNum);
CleanUp9:
/* close libraries */
CloseLibrary((struct Library *)LayersBase);
CleanUp10:
CloseLibrary((struct Library *)GfxBase);
CleanUp11:
CloseLibrary((struct Library *)IntuitionBase);
CleanUp12:
MyDeletePort(ReplyPort);
CleanUp13:
if (StdOut)
WriteAndClose(FAILMSG,sizeof(FAILMSG));
if (PopUpSeg) {
/* if loaded from CLI unload us */
Forbid();
UnLoadSeg(PopUpSeg);
}
CloseLibrary((struct Library *)DOSBase);
}
/***************************************
* WriteAndClose(Text,Length) *
* *
* Input: *
* Text - Text to write to StdOut. *
* Length *
***************************************/
VOID WriteAndClose(Text, Length)
STRPTR Text;
ULONG Length;
{
IMPORT BPTR StdOut;
Write(StdOut,Text,Length);
Delay(DELAYTIME);
Close(StdOut);
StdOut = NULL;
}
/************************************************
* PopUpMainLoop(InputSignals,ReplyPort) *
* *
* Input: *
* InputSignals - Allocated signals. *
* ReplyPort - Port for MENUVERIFY replies *
* Output: *
* none *
************************************************/
VOID PopUpMainLoop(InputSignals)
struct SignalData *const InputSignals;
{
IMPORT struct Window *ActiveWindow;
IMPORT struct Screen *Screen;
IMPORT struct Menu *Menues;
IMPORT struct MsgPort *ReplyPort;
const LONGBITS ReplySig = 1L << (LONG)ReplyPort->mp_SigBit;
WORD NrOfMessages = 0;
WORD Flags = 0;
FOREVER {
const LONGBITS SignalBits = Wait(ReplySig |
InputSignals->MenuUpSig |
InputSignals->MenuDownSig);
if (SignalBits & InputSignals->MenuUpSig) {
ActiveWindow = NULL;
Flags &= QUIT;
}
if (SignalBits & ReplySig) {
struct IntuiMessage *Message;
while (Message = (struct IntuiMessage *)GetMsg(ReplyPort)) {
if (Message->Class & MENUVERIFY) {
if (Message->IDCMPWindow == ActiveWindow)
if (Message->Code == MENUCANCEL)
Flags &= QUIT; /* Verify not OK */
else
Flags |= VERIFYOK;
NrOfMessages--;
FreeMem(Message,sizeof(struct IntuiMessage));
}
else { /* Message->Class == QUITPOPUPMENU or some strange message */
ReplyMsg((struct Message *)Message); /* Message does not belong to this task */
Flags |= QUIT;
}
} /* while */
if (NrOfMessages == 0) {
if (Flags & QUIT)
break;
if (Flags & VERIFYOK) {
PopUpMenu(InputSignals);
Flags = 0;
}
}
}
if ((SignalBits & (InputSignals->MenuUpSig |
InputSignals->MenuDownSig)) == InputSignals->MenuDownSig) {
const LONG Lock = LockIBase(0);
ActiveWindow = IntuitionBase->ActiveWindow;
if (ActiveWindow AND
!(ActiveWindow->Flags & RMBTRAP) AND
(ActiveWindow->MenuStrip)) {
Screen = ActiveWindow->WScreen;
NrOfMessages = SendMessage();
UnlockIBase(Lock);
if (NrOfMessages == 0)
PopUpMenu(InputSignals);
else
Flags |= VERIFYOK;
}
else
UnlockIBase(Lock);
}
} /* FOREVER */
}
/*******************************************************
* SendMessage() - Send MENUVERIFY message *
* to all windows on screen with MENUVERIFY flag set. *
* IBase must be locked!! *
* Input: *
* none *
* Output: *
* return - Messages sent. *
*******************************************************/
WORD SendMessage()
{
IMPORT struct Window *const ActiveWindow;
IMPORT struct MsgPort *ReplyPort;
IMPORT struct Screen *Screen;
struct Window *Window;
WORD NrOfMessages = 0;
Window = Screen->FirstWindow;
do {
if (Window->IDCMPFlags & MENUVERIFY) {
struct IntuiMessage *const Message =
BuildIntuiMsg(ReplyPort, MENUVERIFY,
(Window == ActiveWindow) ? MENUHOT : MENUWAITING);
if (Message) {
CurrentTime(&Message->Seconds,&Message->Micros);
Message->IDCMPWindow = Window;
PutMsg(Window->UserPort,(struct Message *)Message);
NrOfMessages++;
}
}
}
while (Window = Window->NextWindow);
return (NrOfMessages);
}
/***************************************
* BuildIntuiMsg(ReplyMsg,Class,Code) *
* *
* Input: *
* ReplyPort *
* Class *
* Code *
* Output: *
* return - IntuiMessage *
***************************************/
struct IntuiMessage *BuildIntuiMsg(ReplyPort,Class,Code)
struct MsgPort *const ReplyPort;
ULONG Class;
UWORD Code;
{
struct IntuiMessage *const Message =
AllocMem(sizeof(struct IntuiMessage),MEMF_PUBLIC | MEMF_CLEAR);
if (Message) {
Message->ExecMessage.mn_Node.ln_Type = NT_MESSAGE;
Message->ExecMessage.mn_ReplyPort = ReplyPort;
Message->ExecMessage.mn_Length = sizeof(struct IntuiMessage) -
sizeof(struct Message);
Message->Class = Class;
Message->Code = Code;
}
return (Message);
}
/*******************************
* MyCreatePort(Name, Pri) *
* MyDeletePort(Port) *
* *
* Replacements for amiga.lib *
*******************************/
struct MsgPort *MyCreatePort(Name)
STRPTR Name;
{
UBYTE SigBit;
if ((SigBit = AllocSignal(-1)) != -1) {
struct MsgPort *const Port = AllocMem(sizeof(struct MsgPort),
MEMF_CLEAR | MEMF_PUBLIC);
if (Port) {
Port->mp_Node.ln_Name = Name;
Port->mp_Node.ln_Pri = 0;
Port->mp_Node.ln_Type = NT_MSGPORT;
Port->mp_Flags = PA_SIGNAL;
Port->mp_SigBit = SigBit;
Port->mp_SigTask = (struct Task *)FindTask(0);
AddPort(Port);
return(Port);
}
else
FreeSignal((LONG)SigBit);
}
return(NULL);
}
VOID MyDeletePort(Port)
struct MsgPort *const Port;
{
RemPort(Port);
FreeSignal((LONG)Port->mp_SigBit);
FreeMem(Port,sizeof(struct MsgPort));
}